<?php
// +----------------------------------------------------------------------
// | ThinkSNS
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://www.thinksns.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: Daniel Yang <desheng.young@gmail.com>
// +----------------------------------------------------------------------
//

/**
 +------------------------------------------------------------------------------
 * SecurityService 系统安全性检验服务
 * 实现对系统所有GET/POST参数的捕获，以及按照给定规则对系统的攻击测试
 * 为系统安全性测试提供支持
 +------------------------------------------------------------------------------
 * @category	addons
 * @package		addons
 * @subpackage  services
 * @author		Daniel Yang <desheng.young@gmail.com>
 * @version		$Id$
 +------------------------------------------------------------------------------
 */

class SecurityService extends Service{
	private $dao     = array();
	private $data    = array();
	private $single  = true;   //true:每种类型只存储1个数据 | false:记录所有数据
	private $rules	 = array();
	
	/**
     +----------------------------------------------------------
     * 架构函数
     +----------------------------------------------------------
     * @author daniel制作
     * @access public
     +----------------------------------------------------------
     */
	public function __construct() {
		//1.判断是否安装、是否运行该服务，系统服务可以不做判断
		//2.服务初始化
		$this->init();
		$this->run();
	}

	//服务初始化
	public function init() {
		return true;

		$this->dao = M('security');

		//组装data
		$this->data['app'] = self::_getApp();
		$this->data['mod'] = self::_getModule();
		$this->data['act'] = self::_getAction();
		$this->data['type'] = $_SERVER['REQUEST_METHOD'];
		$_SERVER['REQUEST_METHOD'] == 'GET'  && $request = $_GET;
		$_SERVER['REQUEST_METHOD'] == 'POST' && $request = $_POST;
		unset($request['app']);
		unset($request['mod']);
		unset($request['act']);
		foreach($request as $k => $v) {
			$this->data['key'][]   = htmlspecialchars($k);
			$this->data['value'][] = htmlspecialchars($v);
		}

		//初始化攻击规则
		$this->rules = array(
			"'%27%25%27", "--%2d%2d", "' AND '1'='1", 
			"<>%3c%3e%253c%253e", "'\"%27%22%2527%2522", "()%28%29%2528%2529",
		);
	}

	//运行服务
	public function run() {
	}

	//运行安全测试
	//$flag: true:全部运行 | false:只运行一条即返回
	public function runSecurity($map = array(), $now = 0, $flag = false) {
		return true;
		//获取数据
		//TODO:把数据缓存or存SESSION
		$data = $this->getSecurity($map);dump($map);dump($data);exit;
		$time_start = $this->microtime_float();

		$cookie_jar = tempnam('./tmp','cookie');
		$ch = curl_init();
		if (!$ch) {
		   die("Couldn't initialize a cURL handle");
		}

		//第一步：登录
		$url = U('home/Public/dologin');
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
		curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_jar);
		curl_setopt($ch, CURLOPT_POST, 1);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_POSTFIELDS, "username=yKF23544&password=zaq1ZAQ!");
		$output = curl_exec($ch);
		curl_close($ch);
		//echo $output;

		//第二步：攻击
		$index = 0; //标记正在执行第几条URL
		$ch2 = curl_init();
		curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 0);
		curl_setopt($ch2, CURLOPT_POST, 1);
		curl_setopt($ch2, CURLOPT_HEADER, 0);
		curl_setopt($ch2, CURLOPT_COOKIEFILE, $cookie_jar);
		foreach($data as $v) {
			//按攻击类型循环
			foreach($this->rules as $rule) {
				//按参数列表循环
				foreach($v['param'] as $k => $param) {
					if($flag == false && $index < $now) {
						$index ++;
						continue;
					}
					$tmp = $v['param'];
					$v['param'][$k] = $param . $rule;
					$url2 = U($v['app'] . '/' . ucfirst($v['mod']) . '/' . $v['act']);
					if($v['type'] == 'GET') {
						//组装完整的url（包含GET参数）
						foreach($v['param'] as $k2 => $v2) {
							$get_params[]  = $k2 . '=' . $v2;
						}
						$url2 .= '&' . implode('&', $get_params);
						$url2 = U('wiki/Do/refreshEditLock',array('aaaa'=>'bbbb'));
						dump($url2);
						$ch = curl_init($url2);
						curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
						curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
						curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_jar);
						$output2 = curl_exec($ch);dump($output2);curl_close($ch);curl_close($ch2);return 'xxxx';
						//$fh = fopen("out.html", 'w');
						//fwrite($fh, $output);
						//fclose($fh);
						curl_close($ch);
					}else {
						curl_setopt($ch2, CURLOPT_URL, $url2);
						curl_setopt($ch2, CURLOPT_POSTFIELDS, $v['param']);
						$output2 = curl_exec($ch2);
						//$info2   = curl_getinfo($ch2);
						//echo $output2;
					}
					if($flag == false) {
						curl_close($ch2);
						$time = $this->microtime_float() - $time_start;
						echo 'This search takes ' . $time . ' seconds.';
						return $now + 1;
					}
					$v['param'] = $tmp;
				}
			}
		}
		curl_close($ch2);

		$time = $this->microtime_float() - $time_start;
		echo 'This search takes ' . $time . ' seconds.';
		return 0;
	}

	//添加数据
	public function save() {
		return true;

		if(!$this->isValidMVC($this->data)) return false;

		//TODO ignored=1时

		//判定同一组数据
		$single_flag = $this->dao->field('id')->order('id DESC')->limit(1)->findAll();
		$single_flag = $single_flag[0]['id'];

		foreach($this->data['key'] as $k => $v) {
			if($this->single != false) {
				//删除旧记录
				$map['app']  = $this->data['app'];
				$map['mod']  = $this->data['mod'];
				$map['act']  = $this->data['act'];
				$map['type'] = $this->data['type'];
				$map['key']  = $v;
				$this->dao->where($map)->delete();
			}

			//添加新记录
			$sql = 'INSERT INTO ' . C('DB_PREFIX') . 'security (`app`,`mod`,`act`,`type`,`key`,`value`,`group_flag`)  VALUES ( "' .
					$this->data['app']  . '","' . 
					$this->data['mod']  . '","' . 
					$this->data['act']  . '","' . 
					$this->data['type'] . '","' . 
					$v . '","' . 
					$this->data['value'][$k] . '","' . 
					$single_flag . '" )';

			//插入数据列表
			$result	= $this->dao->execute($sql);
		}
	}

	//获取数据
	public function getSecurity($map = array()) {
		return true;

		$data = $this->dao->where($map)->order('group_flag DESC')->findAll();
		$res  = array();
		//分组组装参数数组
		foreach($data as $k => $v) {
			$group[$v['group_flag']][$v['key']] = $v['value'];
		}
		//组装实际的url和参数的对应数组
		foreach($data as $k => $v) {
			if(!isset($group[$v['group_flag']])) continue;
			$res[] = array(
				'app'	=> $v['app'],
				'mod'	=> $v['mod'],
				'act'	=> $v['act'],
				'type'	=> $v['type'],
				'param'	=> $group[$v['group_flag']],
			);
			unset($group[$v['group_flag']]);
		}
		return $res;
	}

	//MVC参数是否有效
	public function isValidMVC($data) {
		return true;

		if(!is_dir(SITE_PATH . '/apps/' . $data['app'])) 
			return false;
		if(!is_file(SITE_PATH . '/apps/' . $data['app'] . '/Lib/Action/' . $data['mod'] . 'Action.class.php')) 
			return false;
		return true;
	}

	public function microtime_float() {
		list($usec, $sec) = explode(" ", microtime());
		return ((float)$usec + (float)$sec);
	}

	/**
	 +----------------------------------------------------------
	 * 获得实际的应用名称
	 +----------------------------------------------------------
	 * @access private
	 +----------------------------------------------------------
	 * @return string
	 +----------------------------------------------------------
	 */
	static private function _getApp() {
		//应用路径解析
		if(isset($_GET['app'])){
			//判断开放的应用列表，进行必要的应用名过滤
			return strtolower(str_replace(array('/','\\'),'',strip_tags(urldecode($_GET['app']))));
		}else{
			return 'home';
		}
	}

	/**
	 +----------------------------------------------------------
	 * 获得实际的模块名称
	 +----------------------------------------------------------
	 * @access private
	 +----------------------------------------------------------
	 * @return string
	 +----------------------------------------------------------
	 */
	static private function _getModule() {
		$var	=  C('VAR_MODULE');
		$module = !empty($_POST[$var]) ? $_POST[$var] : (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE'));
		if(C('URL_CASE_INSENSITIVE')) {
			$module = ucfirst($module);
			// 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块
			$module = ucfirst(parse_name($module,1));
		}
		return $module;
	}

	/**
	 +----------------------------------------------------------
	 * 获得实际的操作名称
	 +----------------------------------------------------------
	 * @access private
	 +----------------------------------------------------------
	 * @return string
	 +----------------------------------------------------------
	 */
	static private function _getAction() {
		$var  =  C('VAR_ACTION');
		$action   = !empty($_POST[$var]) ? $_POST[$var] : (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION'));
		return $action;
	}



	/* 后台管理相关方法 */

	//启动服务，未编码
	public function _start(){
		return true;
	}

	//停止服务，未编码
	public function _stop(){
		return true;
	}

	//卸载服务，未编码
	public function _install(){
		return true;
	}

	//卸载服务，未编码
	public function _uninstall(){
		return true;
	}
}
?>